"""
环境搭建说明：
test_sdk_api放在/data路径，将xtra文件放到/data路径下，多个XTRA文件修改名字后放到/data路径下，并在mian中列表增加XTRA文件名称。
需要设置项：设置模块的DEBUG口
测试前修改修改/etc/gps.conf，将debug level 改为4，
设置ql_dm_set_mssr_level等级为3，
重启生效

"""

import serial
import time
import os
import sys
import random
import re
import subprocess
import threading


# 定义常量
DEBUG_PORT = "COM4"
AT_PORT = "COM66"
BAUDRATE = 115200
# 定义变量
at_serial = None
debug_serial = None
# 记录运行次数
runTimes = 0
# log文件
DEBUG_LOG = ""
ADB_LOG = ""
AT_LOG = ""


# 创建日志文件
def createLogFile():
    global DEBUG_LOG, ADB_LOG, AT_LOG
    timestamp = time.strftime("%Y-%m-%d_%H_%M_%S", time.localtime())
    DEBUG_LOG = f"DEBUG_LOG_{timestamp}.log"
    # ADB_LOG = f"ADB_LOG_{timestamp}.log"
    # AT_LOG = f"AT_LOG_{timestamp}.log"

    with open(DEBUG_LOG, "w", encoding="utf-8") as file:
        file.write("DEBUG 日志开始记录...\n")

    # with open(ADB_LOG, 'w', encoding='utf-8') as file:
    #     file.write("ADB 日志开始记录...\n")

    # with open(AT_LOG, 'w', encoding='utf-8') as file:
    #     file.write("AT 日志开始记录...\n")


# 写日志
def write_log(log, logFile):
    with open(logFile, "a", encoding="utf-8") as file_object:
        file_object.write(
            str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
            + "\r\n"
            + log
            + "\r\n"
        )
        now_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        print("[" + now_time + "]" + " " + log)


# Send at instruction
def at_write(command, timeout, at_port_opened, at_result, RDY=0, CPIN=0):
    at_command = command.encode("UTF-8")
    at_port_opened.write(at_command)


# 读取at口返回
def at_read(serial_port, logFile=""):
    rec_str = ""
    while True:
        time.sleep(1)
        lenth = serial_port.inWaiting()
        if lenth > 0:
            rec_str = serial_port.read(size=lenth)
            try:
                rec_str = re.sub("\\x1b.*?m", "", rec_str.decode("UTF-8"), 0, re.I)
                if logFile != "":
                    with open(logFile, "a") as file_object:
                        rec_str = (
                            str(time.time())
                            + ":"
                            + str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
                            + "\r\n"
                            + rec_str
                        )
                        file_object.write(
                            str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
                            + "\r\n"
                            + rec_str
                            + "\r\n"
                        )
                return rec_str
            except:
                return ""
        else:
            break
    return rec_str


# 登录设备
def loginDevice():
    global DEBUG_LOG
    # 确认登录失败的条件，或者，不可能失败
    while True:
        #   print("等待登录... ... ")
        write_log("等待登录... ... ", DEBUG_LOG)
        time.sleep(3)
        at_write("\r\n", 3, debug_serial, "OK")
        result = at_read(debug_serial)

        with open(DEBUG_LOG, "a") as file_object:
            file_object.write(result)

        if "login:" in result:
            at_write("root\r\n", 3, debug_serial, "OK")
            #    print("账号输入成功")
            write_log("账号输入成功", DEBUG_LOG)
            time.sleep(2)
            at_write("oelinux123\r\n", 3, debug_serial, "OK")
            #    print("密码输入成功")
            write_log("密码输入成功", DEBUG_LOG)
        elif "~ #" in result:
            #    print("登录成功")
            write_log("登录成功", DEBUG_LOG)
            break
        else:
            continue


# 检查debug口通信状态
def check_port_status():
    global debug_serial
    if debug_serial == None:
        try:
            debug_serial = serial.Serial(DEBUG_PORT, BAUDRATE)
        except:
            print("端口连接失败，请检查端口")
            sys.exit()


# 写入运行次数到日志
def writeRuntimesToLog():
    global runTimes
    with open(DEBUG_LOG, "a+") as file_object:
        file_object.write(
            "\r\n{} runtimes: {} {}\r\n".format("<" * 20, runTimes, ">" * 20)
        )
    #  print("\r\n{} runtimes: {} {}\r\n".format("<"*20,runTimes,">"*20))
    with open(AT_LOG, "a+") as file_object:
        file_object.write(
            "\r\n{} runtimes: {} {}\r\n".format("<" * 20, runTimes, ">" * 20)
        )
    #  print("\r\n{} runtimes: {} {}\r\n".format("<"*20,runTimes,">"*20))
    with open(ADB_LOG, "a+") as file_object:
        file_object.write(
            "\r\n{} runtimes: {} {}\r\n".format("<" * 20, runTimes, ">" * 20)
        )
    print("\r\n{} runtimes: {} {}\r\n".format("<" * 20, runTimes, ">" * 20))
    runTimes += 1


# 发送AT指令
def send_at_command(command):
    # 打开串口
    ser = serial.Serial(AT_PORT, BAUDRATE)
    ser.write((command + "\r\n").encode())
    ser.write(("\r\n").encode())
    time.sleep(6)
    response = ser.read_all().decode()
    ser.close()
    # write_log(f"at指令{command}执行结果:{response}",AT_LOG)
    with open(AT_LOG, "a", encoding="utf-8") as file_object:
        file_object.write(
            str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
            + "\r\n"
            + response
            + "\r\n"
        )
    return response


# 发送adb命令
def send_adb_command(command):
    try:
        # 使用 subprocess 模块执行 adb shell 命令
        result = subprocess.run(
            ["adb", "shell", command], capture_output=True, text=True
        )
        with open(ADB_LOG, "a", encoding="utf-8") as file_object:
            file_object.write(
                str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
                + "\r\n"
                + result.stdout
                + "\r\n"
            )
        # 返回命令的输出结果
        return result.stdout
    except Exception as e:
        return str(e)


# 写入运行次数到日志
def writeRuntimesToLog():
    global runTimes
    with open(DEBUG_LOG, "a+") as file_object:
        file_object.write(
            "\r\n{} runtimes: {} {}\r\n".format("<" * 20, runTimes, ">" * 20)
        )
    print("\r\n{} runtimes: {} {}\r\n".format("<" * 20, runTimes, ">" * 20))
    runTimes += 1


# 进入测试接口
def intoTestInterface_testsdk(debug_serial, logFile):
    at_write("cd /data\r\n./test_sdk_api\r\n", 3, debug_serial, "OK")
    write_log("进入测试接口", logFile)
    time.sleep(2)


# 退出测试接口
def exit_testsdk(debug_serial, logFile):
    at_write("-1\n-1\n", 3, debug_serial, "OK")
    result = at_read(debug_serial, logFile)


# 返回测试接口
def back_testsdk(debug_serial, logFile):
    at_write("-1\n", 3, debug_serial, "OK")
    result = at_read(debug_serial, logFile)


# modem 重启
def modem_restart():
    write_log("开始modem 重启", DEBUG_LOG)
    at_write("7\n", 3, debug_serial, "OK")
    time.sleep(2)
    at_read(debug_serial, DEBUG_LOG)
    at_write("0\n", 3, debug_serial, "OK")
    time.sleep(2)
    at_read(debug_serial, DEBUG_LOG)
    at_write("28\n", 3, debug_serial, "OK")
    time.sleep(2)
    result = at_read(debug_serial, DEBUG_LOG)
    if "ret = 0" in result:
        write_log("modem 重启成功", DEBUG_LOG)
        write_log("等待modem 启动", DEBUG_LOG)
    else:
        write_log("modem 重启失败", DEBUG_LOG)


# 注入XTRA
def inject_xtra(xtra_name):
    write_log(f"开始注入XTRA{xtra_name}", DEBUG_LOG)
    at_write("12\n", 3, debug_serial, "OK")
    time.sleep(2)
    at_read(debug_serial, DEBUG_LOG)
    at_write("0\n", 3, debug_serial, "OK")
    time.sleep(2)
    at_read(debug_serial, DEBUG_LOG)
    at_write("11\n", 3, debug_serial, "OK")
    time.sleep(2)
    at_read(debug_serial, DEBUG_LOG)
    at_write("/data/{}\n".format(xtra_name), 3, debug_serial, "OK")
    time.sleep(3)
    result = at_read(debug_serial, DEBUG_LOG)
    if "Success" in result:
        write_log("XTRA 注入成功", DEBUG_LOG)
    else:
        write_log("XTRA 注入失败", DEBUG_LOG)


def main():
    # 配置文件和常量
    xtra_names = ["xtra3grcej.bin"]  # 在这里增加注入的xtra文件名
    sleep_duration = 30
    try:
        # 初始化设备和日志环境
        check_port_status()  # 确保串口已连接
        createLogFile()  # 创建日志文件
        print(f"DEBUG_LOG: {DEBUG_LOG}")  # 打印日志路径确认日志文件
        check_port_status()  # 再次确认串口连接
        loginDevice()  # 登录设备
        intoTestInterface_testsdk(debug_serial, DEBUG_LOG)  # 进入测试界面

        # 主测试循环
        while True:

            writeRuntimesToLog()  # 写运行时间到日志
            for xtra_name in xtra_names:
                modem_restart()  # 调制解调器重启
                time.sleep(sleep_duration)  # 等待
                back_testsdk(debug_serial, DEBUG_LOG)  # 返回测试界面
                inject_xtra(xtra_name)  # 注入 XTRA 文件
                back_testsdk(debug_serial, DEBUG_LOG)  # 返回测试界面

    except KeyboardInterrupt:
        print("程序被手动终止")
    except Exception as e:
        print(f"发生异常: {e}")


if __name__ == "__main__":
    main()
